/**
 * Copyright (C) 2009+ Spark Zheng
 *
 * @file        src/connection.h 
 * @date        2010-04-05
 * @brief	general_network
 * @see         dserver
 * @history
 */

#ifndef _DSERVER_CONNECTION_H
#define _DSERVER_CONNECTION_H

#ifdef __cplusplus
extern "C" {
#endif

#include <event.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <dlib/global.h>
#include <dlib/list.h>
#include <dlib/lock.h>
		
/** define of dserver_conn_t & dserver_cpool_t */
#include "prot_types.h"

/** The default connection-pool number */
#ifndef	CONN_INIT_NUM
#define CONN_INIT_NUM		128U
#endif

/**
 * TCP/SCTP-stream needed | UDP/SCTP-dgram needed
 * each client associated with a connection-struct which be organized in cpool
 * connection-struct is the most important struct in stream context,
 * it could be argument passing to protocol-modules or filter-modules,
 * it could be owned by special thread.
 */
struct connection {
	/** general parameters */
	prot_node_t	*c_prot_node;	/** current protocol node pointer */

	/** used in tcp-protocol */
	int 		c_cfd;		/** client-fd (for TCP/SCTP-stream) */
	struct event	c_event;	/** event structure (for TCP/SCTP-stream) */

	/** used in all protocol */
	struct sockaddr	c_csa;		/** client sockaddr */
	socklen_t	c_csa_len;	/** client sockaddr length */

	char		c_rbuf[DSERVER_RX_BUFLEN];	/** read buffer */
	uint32_t	c_rsize;	/** readed data size */

	char		c_head[DSERVER_HEAD_SIZE];	/** dserver header, a hint for write */
	char		c_wbuf[DSERVER_TX_BUFLEN];	/** write buffer */
	uint32_t	c_wsize;	/** write data size */

	void		*c_data;	/** the relay data pointer, special usage */
	hlist_node_t	c_node;		/** freelist iterator (for TCP/SCTP-stream) */
};

struct connection_pool {
	uint32_t	cp_max;		/** the max conn structure */
	uint32_t	cp_total;	/** total number of alloced conn */
	uint32_t	cp_curr;	/** current number in freelist */
	hlist_head_t	c_head;		/** freelist head */
	dlib_lock_t	cp_lock;	/** cpool lock */
};

/** setup the connection on creating */
static inline void dserver_conn_setup(dserver_conn_t *conn)
{
	conn->c_csa_len = sizeof(conn->c_csa);
	conn->c_rsize = 0;
	conn->c_wsize = 0;
	conn->c_data = NULL;
	return;
}

/** cleanup conn for UDP */
static inline void dserver_conn_cleanup(dserver_conn_t *conn)
{
	conn->c_csa_len = sizeof(conn->c_csa);
	conn->c_rsize = 0;
	conn->c_wsize = 0;
	conn->c_data = NULL;
	return;
}

/** destroy conn when server is down */
static inline void dserver_conn_destroy(dserver_conn_t *conn)
{
	UNUSED_PARAM(conn);
	return;
}

/**
 * dserver_cpool_init
 * @brief construct of cpool
 * @param max_conn: the max connection number
 */
extern dserver_cpool_t *dserver_cpool_init(uint32_t max_conn);

/**
 * dserver_cpool_exit
 * @brief destruct of cpool
 * @param cpool: cpool struct
 */
extern void dserver_cpool_exit(dserver_cpool_t *cpool);

/**
 * dserver_conn_fetch
 * @brief get a connection struct from cpool
 * @return a connection struct or NULL
 * @param cpool: cpool struct
 */
extern dserver_conn_t *dserver_conn_fetch(dserver_cpool_t *cpool);

/**
 * dserver_conn_restore
 * @brief restore a connection struct
 * @param cpool: cpool struct 
 * @param conn: connection struct
 */
extern int dserver_conn_restore(dserver_cpool_t *cpool, dserver_conn_t *conn);

#ifdef __cplusplus
}
#endif
#endif
